// Copyright 2017 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ------------------------------------------------------------------
// Modification history:
// feature: support message brief record
// feature: QoS Profile Inheritance and Composition
// feature: simplify xml profile
// ------------------------------------------------------------------

#ifndef XMLPARSER_XMLPROFILEMANAGER_H_
#define XMLPARSER_XMLPROFILEMANAGER_H_

#include <xmlparser/attributes/XMLParticipantAttributes.h>
#include <xmlparser/attributes/XMLPublisherAttributes.h>
#include <xmlparser/attributes/XMLSubscriberAttributes.h>
#include <xmlparser/attributes/XMLTopicAttributes.h>

#include <xmlparser/XMLParserCommonPart.h>
#include <xmlparser/XMLParserPart.h>

#include <string>
#include <map>
#include <mutex>

namespace vbsutil {
namespace xmlparser {

using set_flags_map_t = std::map<std::string, std::vector<bool>>;

using participant_map_t = std::map<std::string, up_participant_t>;

using publisher_map_t = std::map<std::string, up_publisher_t>;

using subscriber_map_t = std::map<std::string, up_subscriber_t>;

using topic_map_t = std::map<std::string, up_topic_t>;

using xmlfiles_map_t = std::map<std::string, XMLP_ret>;

/**
 * Class XMLProfileManagerPart, used to make available profiles from XML file.
 * @ingroup XMLPROFILEMANAGER_MODULE
 */
class XMLProfileManagerPart {
    friend class XMLParserpart;

 public:
    RTPS_DllAPI static XMLP_ret loadXMLFile(const std::string& filename);

    RTPS_DllAPI static XMLP_ret loadXMLString(const char* data, size_t length);

    RTPS_DllAPI static XMLP_ret loadXMLNode(tinyxml2::XMLDocument& doc);

    /**
     * Search for the profile specified and fill the structure.
     * @param profile_name Name for the profile to be used to fill the structure.
     * @param atts Structure to be filled.
     * @param log_error Flag to log an error if the profile_name is not found.
     * @return XMLP_ret::XML_OK on success, XMLP_ret::XML_ERROR in other case. Defaults true.
     */
    RTPS_DllAPI static XMLP_ret getParticipantAttributes(const std::string& profile_name, ParticipantAttributes& atts,
                                                         bool log_error = true);
    /**
     * Search for the profile specified and fill the structure.
     * @param profile_name Name for the profile to be used to fill the structure.
     * @param atts Structure to be filled.
     * @param log_error Flag to log an error if the profile_name is not found.
     * @return XMLP_ret::XML_OK on success, XMLP_ret::XML_ERROR in other case. Defaults true.
     */
    RTPS_DllAPI static XMLP_ret getPublisherAttributes(const std::string& profile_name, PublisherAttributes& atts,
                                                       bool log_error = true);

    /**
     * Search for the profile specified and fill the structure.
     * @param profile_name Name for the profile to be used to fill the structure.
     * @param atts Structure to be filled.
     * @param log_error Flag to log an error if the profile_name is not found.
     * @return XMLP_ret::XML_OK on success, XMLP_ret::XML_ERROR in other case. Defaults true.
     */
    RTPS_DllAPI static XMLP_ret getSubscriberAttributes(const std::string& profile_name, SubscriberAttributes& atts,
                                                        bool log_error = true);

    /**
     * Search for the profile specified and fill the structure.
     * @param profile_name Name for the profile to be used to fill the structure.
     * @param atts Structure to be filled.
     * @return XMLP_ret::XML_OK on success, XMLP_ret::XML_ERROR in other case.
     */
    RTPS_DllAPI static XMLP_ret getTopicAttributes(const std::string& profile_name, TopicAttributes& atts);

    // !Add a new transport instance along with its id.
    RTPS_DllAPI static bool insertTransportById(const std::string& transport_id, sp_transport_t transport);

    // !Retrieves a transport instance by its id.
    RTPS_DllAPI static sp_transport_t getTransportById(const std::string& transport_id);

    /**
     * Deletes the XMLProfileManagerPart instance.
     * EDDS's Domain calls this method automatically on its destructor, but
     * if using XMLProfileManagerPart outside of EDDS, it should be called manually.
     */
    RTPS_DllAPI static void DeleteInstance() {
        // ertps::types::DynamicTypeBuilderFactory::delete_instance();
        participant_profiles_.clear();
        publisher_profiles_.clear();
        subscriber_profiles_.clear();
        participant_profile_set_flags_.clear();
        publisher_profile_set_flags_.clear();
        subscriber_profile_set_flags_.clear();
        topic_profiles_.clear();
        xml_files_part_.clear();
        userTransportsId.clear();
        XMLParserpart::parsed_profiles_.clear();
        XMLParserpart::parsed_consumers_.clear();
        transport_profiles_.clear();
    }

    /**
     * @brief Get the Participant Profiles object
     *
     * @return participant_map_t&
     */
    RTPS_DllAPI static participant_map_t& GetParticipantProfiles() { return participant_profiles_; }

    /**
     * @brief Get the Publisher Profiles object
     *
     * @return publisher_map_t&
     */
    RTPS_DllAPI static publisher_map_t& GetPublisherProfiles() { return publisher_profiles_; }

    /**
     * @brief Get the Subscriber Profiles object
     *
     * @return subscriber_map_t&
     */
    RTPS_DllAPI static subscriber_map_t& GetSubscriberProfiles() { return subscriber_profiles_; }

    /**
     * @brief Get the Topic Profiles object
     *
     * @return topic_map_t&
     */
    RTPS_DllAPI static topic_map_t& GetTopicProfiles() { return topic_profiles_; }

    RTPS_DllAPI static ParticipantAttributes& getDefaultParticipantAttributes();

    RTPS_DllAPI static PublisherAttributes& getDefaultPublisherAttributes();

    RTPS_DllAPI static SubscriberAttributes& getDefaultSubscriberAttributes();

    RTPS_DllAPI static TopicAttributes& getDefaultTopicAttributes();

    RTPS_DllAPI static XMLP_ret extractParticipantProfile(up_base_node_t& profile, const std::string& profile_lib_name,
                                                          std::vector<bool>& set_flags);

    RTPS_DllAPI static XMLP_ret extractPublisherProfile(up_base_node_t& profile, const std::string& profile_lib_name,
                                                        std::vector<bool>& set_flags);

    RTPS_DllAPI static XMLP_ret extractSubscriberProfile(up_base_node_t& profile, const std::string& profile_lib_name,
                                                         std::vector<bool>& set_flags);

    RTPS_DllAPI static XMLP_ret extractTopicProfile(up_base_node_t& profile);

    static bool participantProfilesEmpty();

    static participant_map_t participant_profiles_;

    static set_flags_map_t participant_profile_set_flags_;

    static publisher_map_t publisher_profiles_;

    static set_flags_map_t publisher_profile_set_flags_;

    static subscriber_map_t subscriber_profiles_;

    static set_flags_map_t subscriber_profile_set_flags_;

    static topic_map_t topic_profiles_;

    static up_base_node_t xmlFile_root_node;

    static up_base_node_t xmlString_root_node;

    static up_base_node_t xmlNode_root_node;

    static std::vector<std::string> userTransportsId;

    static bool isLoadBuiltinProfileStr;

    static std::string currentXmlPath;

    static sp_transport_map_t transport_profiles_;

 private:
    static bool getInheritanceCombinationBaseInfo(std::string name);

    static void setDefaultProfile(const std::string& name);

    // static BaseNode* root;

    // static LibrarySettingsAttributes library_settings_;

    static xmlfiles_map_t xml_files_part_;

    static std::mutex mtx_xml_participant_profiles_;

    static std::mutex mtx_xml_publisher_profiles_;

    static std::mutex mtx_xml_subscriber_profiles_;

    static std::mutex mtx_xml_topic_profiles_;

    static std::mutex mtx_xml_transport_profiles_;

    static std::recursive_mutex mtx_xml_files_part_;
};

}  // namespace xmlparser
}  // namespace vbsutil

#endif  // INCLUDE_ERTPS_XMLPARSER_XMLPROFILEMANAGER_H_
